package org.fujene.diskblock.repli;

import static org.fujene.diskblock.repli.ReplicateDictionaryDiskBlock.Type.*;

import java.io.File;
import java.io.UnsupportedEncodingException;

import org.fujene.diskblock.DiskBlock;
import org.fujene.memoryblock.MemoryBlock;
import org.fujene.memoryblock.repli.ReplicateDictionaryBlock;
import org.fujene.structure.Constants;
import org.fujene.structure.ExtendTerm;
import org.fujene.structure.LookupPointer;
import org.fujene.toolbox.ByteConverter;

public class ReplicateDictionaryDiskBlock extends DiskBlock{

	public ReplicateDictionaryDiskBlock(File fileDesc) throws Exception{
		super(fileDesc);
	}

	public ReplicateDictionaryDiskBlock(ReplicateDictionaryBlock memBlock, String dir){
		super(memBlock, dir);
	}

	public enum Type{
		ALL, NEXT, DOCID, INVINDEX, STR, DOCFRQ,
	}

	private class DictionaryTerm{
		private LookupPointer nextTerm;
		private int docfreq;
		private LookupPointer[] invIndex;
		private long[] firstID;
		private int strlen;
		private String str;
		private int opt_type;

		// データ読み込み用
		public DictionaryTerm(int from, Type type) throws Exception{
			opt_type = getOption(1);

			if (type == ALL || type == NEXT)
				this.nextTerm = ByteConverter.getPtr(getBody(from, PTR));
			else this.nextTerm = Constants.EMPTY_PTR;
			from += PTR;

			if (type == ALL || type == DOCFRQ)
				this.docfreq = ByteConverter.byteToInt(getBody(from, DOCFREQ));
			else this.nextTerm = Constants.EMPTY_PTR;
			from += DOCFREQ;

			if (type == ALL || type == INVINDEX || type == DOCID){
				this.invIndex = new LookupPointer[opt_type];
				this.firstID = new long[opt_type];
				for(int i = 0; i < opt_type; i++){
					this.invIndex[i] = ByteConverter.getPtr(getBody(from, PTR));
					from += PTR;
					this.firstID[i] = ByteConverter.byteToLong(getBody(from, 8));
					from += 8;
				}
			}

			if (type == ALL || type == STR){
				this.strlen = ByteConverter.byteToInt(getBody(from, STRLEN));
				from += STRLEN;
				try{
					this.str = new String(getBody(from, strlen), "UTF-8");
				}
				catch(UnsupportedEncodingException e){}
			}
		}
	}

	public LookupPointer getDocIDPointer(int index, int ptr) throws Exception{
		DictionaryTerm ptredDic = new DictionaryTerm(ptr, Type.DOCID);

		if (ptredDic.invIndex[index].equals(Constants.EMPTY_PTR))
			return null;
		else return ptredDic.invIndex[index];
	}

	public long getFirstPointer(int index, int ptr) throws Exception{
		DictionaryTerm ptredDic = new DictionaryTerm(ptr, Type.DOCID);

		return ptredDic.firstID[index];
	}

	// 情報読み込み
	public ExtendTerm getTerm(int ptr, int indexType) throws Exception{
		DictionaryTerm ptredDic = new DictionaryTerm(ptr, ALL);

		if (ptredDic.nextTerm.equals(Constants.EMPTY_PTR)) ptredDic.nextTerm = null;
		if (ptredDic.invIndex[indexType].equals(Constants.EMPTY_PTR)) ptredDic.invIndex[indexType] = null;

		return new ExtendTerm(ptredDic.str, ptredDic.nextTerm, null, new LookupPointer(this.getID(), ptr),
				-1, ptredDic.invIndex, ptredDic.firstID, ptredDic.docfreq);
	}

	public int getTermCount() throws Exception{
		return this.getOption(0);
	}

	public LookupPointer getNextPointer(int ptr) throws Exception{
		DictionaryTerm ptredDic = new DictionaryTerm(ptr, NEXT);

		if (ptredDic.nextTerm.equals(Constants.EMPTY_PTR))
			return null;
		else return ptredDic.nextTerm;
	}

	public LookupPointer getInvIndexPointer(int ptr, int index) throws Exception{
		DictionaryTerm ptredDic = new DictionaryTerm(ptr, INVINDEX);

		if (ptredDic.invIndex[index].equals(Constants.EMPTY_PTR))
			return null;
		else{
			LookupPointer retPtr = ptredDic.invIndex[index];
			retPtr.firstID = ptredDic.firstID[index];
			return ptredDic.invIndex[index];
		}
	}

	public long getFirstID(int ptr, int index) throws Exception{
		DictionaryTerm ptredDic = new DictionaryTerm(ptr, DOCID);

		return ptredDic.firstID[index];
	}

	@Override
	public void readToMemory(MemoryBlock memBlock){
		if (memBlock instanceof ReplicateDictionaryBlock){
			try{
				memBlock.setOption(0, this.getOption(0));
				memBlock.setBody(this.getBody(0, this.bodySize), 0);
				memBlock.setBodyVacancy(this.bodyVacancy);
			}
			catch(Exception e){}
		}
	}

	@Override
	public byte[] getData(){
		throw new NoSuchMethodError("Unimplemented method");
	}
}
